import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.*;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;

/**
 * @description: Git操作器
 * @author: ght
 * @create: 2025-03-31 15:19
 **/
public class GitOperator {

    private String localRepoPath;

    private String repoName;

    private String remoteRepoUrl;

    private String username;

    private String password;

    private Git git;

    public GitOperator(String repositoryPath,String repoName, String remoteRepoUrl, String username, String password) {
        try {
            this.remoteRepoUrl = remoteRepoUrl;
            this.localRepoPath = repositoryPath;
            this.repoName = repoName;
            this.username = username;
            this.password = password;
            File localRepo = new File(buildFullRepoPath());
            if(localRepo.exists()) {
                git = Git.open(new File(buildFullRepoPath()));
            }else {
                git = Git.cloneRepository()
                        .setURI(remoteRepoUrl)   // 设置远程仓库地址
                        .setDirectory(localRepo)  // 指定本地克隆目录
                        .setBranch("master")  // 可选：指定克隆的分支
                        .setCloneAllBranches(true) // 可选：是否克隆所有分支
                        .call();
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException("1");
        }
    }

    public String commitAndPush(String message) {
        try {
            // 添加所有文件到缓冲区
            git.add().addFilepattern(".").call();
            git.commit().setMessage(message).call();
//            Iterable<PushResult> pushResults = git.push().setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password)).call();
//            Iterator<PushResult> iterator = pushResults.iterator();
//            while (iterator.hasNext()) {
//                PushResult pushResult = iterator.next();
//                System.out.println("Push Messages: " + pushResult.getMessages());
//
//                // 遍历远程分支更新状态
//                Collection<RemoteRefUpdate> updates = pushResult.getRemoteUpdates();
//                for (RemoteRefUpdate update : updates) {
//                    System.out.println("更新的远程分支: " + update.getRemoteName());
//                    System.out.println("更新状态: " + update.getStatus());
//
//                    // 判断 push 是否成功
//                    if (update.getStatus() == RemoteRefUpdate.Status.OK ||
//                            update.getStatus() == RemoteRefUpdate.Status.UP_TO_DATE) {
//                        System.out.println("✅ Push 成功!");
//                    } else {
//                        System.out.println("❌ Push 失败: " + update.getStatus());
//                    }
//                }
//            }

            return "ok";
        }catch (Exception e){
            System.out.println("commitAndPush" + e.getMessage());
            throw new RuntimeException("error");
        }
    }

    public String pull(){
        try {
            PullResult pullResult = git.pull().call();
            if(!pullResult.isSuccessful()) {
                return pullResult.toString();
            }
        }catch (Exception e){
            System.out.println("pull" + e.getMessage());
        }
    }
# 这是一个测试
select * from date_time_test
    public String patch(){
        int commitCount = 1; // 生成最近 3 个 commit 的 patch

        try {
            File patch = new File(localRepoPath +"/patch/"+ repoName +"-"+UUID.randomUUID().toString() +".patch");
            if(!patch.exists()){
                patch.createNewFile();
            }
            try (OutputStream outputStream = new FileOutputStream(patch)) {

                // 获取差异
                Iterable<DiffEntry> diffs = git.diff().setOldTree(getTreeIterator(git.getRepository(), "HEAD^")).setNewTree(getTreeIterator(git.getRepository(), "HEAD")).call();

                // 创建输出流，用于生成patch文件
                DiffFormatter diffFormatter = new DiffFormatter(outputStream);
                diffFormatter.setRepository(git.getRepository());

                // 格式化并写入差异
                for (DiffEntry diff : diffs) {
                    diffFormatter.format(diff);
                }
                git.diff().setOutputStream(outputStream).call();
            }
            return patch.getAbsolutePath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";
    }

    private static CanonicalTreeParser getTreeIterator(Repository repository, String commitId) throws IOException {
        // 获取提交的 TreeIterator
        ObjectId commitIdObject = repository.resolve(commitId);
        RevWalk walk = new RevWalk(repository);
        RevCommit commit = walk.parseCommit(commitIdObject);
        RevTree tree = commit.getTree();

        CanonicalTreeParser treeIterator = new CanonicalTreeParser();
        try (ObjectReader reader = repository.newObjectReader()) {
            treeIterator.reset(reader, tree);
        }

        return treeIterator;
    }

    /**
     * 方法有问题
     * @return
     */
    public String rollback(){
        try {
            // 1. reset commits
            // todo 这里有个弊端，如果pull过会有问题
            git.reset().setMode(ResetCommand.ResetType.HARD).setRef("HEAD~1").call(); // 执行 reset --hard
            System.out.println("✅ 本地未 push 的 commit 已回滚！");

            // 2. clean
            git.clean().setCleanDirectories(true).setIgnore(false).call();
            System.out.println("✅ 未跟踪的文件已清理！");
            return "ok";
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("error");
        }

    }

    public void list() throws IOException, GitAPIException {
        Repository repository = git.getRepository();
        // 获取仓库的根目录路径
        File repoRoot = repository.getWorkTree();

//        // 列出工作区文件（未提交的文件）
//        System.out.println("工作区未提交的文件：");
//        listUntrackedFiles(repoRoot);
//
//        // 列出暂存区文件（已git add的文件）
//        System.out.println("暂存区已添加的文件：");
        listStagedFiles(repository);

        // 使用 TreeWalk 遍历已提交的文件（提交历史中的文件）
        System.out.println("已提交的文件：");
        listCommittedFiles(repository, repoRoot);

    }

    // 列出工作区未提交的文件
    private static void listUntrackedFiles(File repoRoot) {
        File[] files = repoRoot.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    listUntrackedFiles(file);  // 递归遍历子目录
                } else {
                    System.out.println("未提交文件: " + file.getAbsolutePath());
                }
            }
        }
    }

    // 列出暂存区（index）中的文件
    private  void listStagedFiles(Repository repository) throws IOException, GitAPIException {
        // 获取状态信息
        Status status = git.status().call();

// 获取已 add（暂存）的文件
        Set<String> addedFiles = status.getAdded();


// 遍历输出文件列表
        for (String file : addedFiles) {
            System.out.println("已添加但未提交的文件: " + file);
        }
    }

    // 列出已提交的文件
    private static void listCommittedFiles(Repository repository, File repoRoot) throws IOException {
        // todo 这里应该只展示二级目录文件列表
        try (TreeWalk treeWalk = new TreeWalk(repository)) {
            treeWalk.addTree(new FileTreeIterator(repository));
            treeWalk.setRecursive(true);

            while (treeWalk.next()) {
                if (FileMode.TREE.equals(treeWalk.getFileMode(0))) {
                    System.out.println(treeWalk.getPathString()+"/");

                } else {
                    System.out.println(treeWalk.getPathString());
                }
            }
        }
    }


    private String buildFullRepoPath(){
        return localRepoPath +"/"+repoName;
    }

    public static void main(String[] args) throws IOException, GitAPIException {
        String repoPath = "/Users/gaohaitao/WorkSpace";
        String repoName = "jzcloud-console";
        String remoteRepoUrl = "https://gitee.com/KaiTuDeShanJuRen/test-sdk.git";

        String username = "1046532003@qq.com";
        String password = "19970515.Gh";
        GitOperator gitOperator = new GitOperator(repoPath,repoName, remoteRepoUrl, username, password);
//        gitOperator.commitAndPush("test add/update/delete patch");
//        System.out.println(gitOperator.patch());
//        gitOperator.rollback();
//        gitOperator.list();
        gitOperator.commitAndPush()
    }
}
